package cn.ztuo.bitrade.processor;


import cn.ztuo.bitrade.component.CoinExchangeRate;
import cn.ztuo.bitrade.entity.CoinThumb;
import cn.ztuo.bitrade.entity.ContractCoin;
import cn.ztuo.bitrade.entity.ContractTrade;
import cn.ztuo.bitrade.entity.KLine;
import cn.ztuo.bitrade.handler.MarketHandler;
import cn.ztuo.bitrade.handler.WebsocketMarketHandler;
import cn.ztuo.bitrade.service.MarketService;
import cn.ztuo.bitrade.util.HttpsUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * 默认交易处理器，产生1mK线信息
 */
@ToString
@Slf4j
public class DefaultCoinProcessorBak implements CoinProcessor {
    private Logger logger = LoggerFactory.getLogger(DefaultCoinProcessorBak.class);
    private String symbol;
    private String baseCoin;
    private KLine currentKLine;
    private List<MarketHandler> handlers;
    private CoinThumb coinThumb;
    private MarketService service;
    private CoinExchangeRate coinExchangeRate;
    //是否暂时处理
    private Boolean isHalt = true;
    private int baseScale;
    private int coinScale;
    private MarketService marketService;
    private ContractCoin coin;

    public DefaultCoinProcessorBak(String symbol, String baseCoin, MarketService marketService, ContractCoin coin) {
        handlers = new ArrayList<>();
        createNewKLine();
        this.baseCoin = baseCoin;
        this.symbol = symbol;
        this.marketService = marketService;
        this.coin = coin;
    }


    public String getSymbol() {
        return symbol;
    }

    @Override
    public void initializeThumb() {
        Calendar calendar = Calendar.getInstance();
        //将秒、微秒字段置为0
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        long nowTime = calendar.getTimeInMillis();
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        long firstTimeOfToday = calendar.getTimeInMillis();
        String period = "1min";
        logger.info("initializeThumb from {} to {}", firstTimeOfToday, nowTime);
        List<KLine> lines = service.findAllKLine(this.symbol, firstTimeOfToday, nowTime, period);
        coinThumb = new CoinThumb();
        synchronized (coinThumb) {
            coinThumb.setSymbol(symbol);

            String mergedUrl = "https://api.btcgateway.pro/swap-ex/market/detail/merged?contract_code=" + coin.getCoinSymbol() + "-USD";
            try {
                String resultStr = HttpsUtil.doGet(mergedUrl);
                JSONObject resultJson = JSON.parseObject(resultStr);
                if (resultJson.containsKey("status") && resultJson.getString("status").equals("ok")) {
                    JSONObject tick = resultJson.getJSONObject("tick");
                    coinThumb.setOpen(tick.getBigDecimal("open").setScale(4, RoundingMode.DOWN));
                    coinThumb.setHigh(tick.getBigDecimal("high").setScale(4, RoundingMode.DOWN));
                    coinThumb.setLow(tick.getBigDecimal("low").setScale(4, RoundingMode.DOWN));
                    coinThumb.setVolume(tick.getBigDecimal("vol").setScale(4, RoundingMode.DOWN));
                } else {
                    for (KLine kline : lines) {
                        if (kline.getOpenPrice().compareTo(BigDecimal.ZERO) == 0) {
                            continue;
                        }
                        if (coinThumb.getOpen().compareTo(BigDecimal.ZERO) == 0) {
                            coinThumb.setOpen(kline.getOpenPrice());
                        }
                        if (coinThumb.getHigh().compareTo(kline.getHighestPrice()) < 0) {
                            coinThumb.setHigh(kline.getHighestPrice());
                        }
                        if (kline.getLowestPrice().compareTo(BigDecimal.ZERO) > 0 && coinThumb.getLow().compareTo(kline.getLowestPrice()) > 0) {
                            coinThumb.setLow(kline.getLowestPrice());
                        }
                        if (kline.getClosePrice().compareTo(BigDecimal.ZERO) > 0) {
                            coinThumb.setClose(kline.getClosePrice());
                        }
                        coinThumb.setVolume(coinThumb.getVolume().add(kline.getVolume()));
                        coinThumb.setTurnover(coinThumb.getTurnover().add(kline.getTurnover()));
                    }
                }
                coinThumb.setChange(coinThumb.getClose().subtract(coinThumb.getOpen()));
                if (coinThumb.getOpen().compareTo(BigDecimal.ZERO) > 0) {
                    coinThumb.setChg(coinThumb.getChange().divide(coinThumb.getOpen(), 4, RoundingMode.UP));
                }
                coinThumb.setCloseStr(coinThumb.getClose().setScale(baseScale, RoundingMode.DOWN).toPlainString());
                coinThumb.setCnyPrice(coinThumb.getClose().multiply(coinThumb.getBaseUsdRate()).multiply(BigDecimal.valueOf(6.8)).setScale(2, BigDecimal.ROUND_HALF_DOWN).toString());
            } catch (Exception e) {
                log.error("initializeThumb is error : {}", e.getMessage());
                logger.info("初始化价格为空");
            }
        }
    }

    public void createNewKLine() {
        currentKLine = new KLine();
        synchronized (currentKLine) {
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);
            //1Min时间要是下一整分钟的
            calendar.add(Calendar.MINUTE, 1);
            currentKLine.setTime(calendar.getTimeInMillis());
            currentKLine.setPeriod("1min");
            currentKLine.setCount(0);
        }
    }

    /**
     * 00:00:00 时重置CoinThumb
     */
    @Override
    public void resetThumb() {
        logger.info("reset coinThumb");
        synchronized (coinThumb) {
            coinThumb.setOpen(BigDecimal.ZERO);
            coinThumb.setHigh(BigDecimal.ZERO);
            //设置昨收价格
            coinThumb.setLastDayClose(coinThumb.getClose());
            //coinThumb.setClose(BigDecimal.ZERO);
            coinThumb.setLow(BigDecimal.ZERO);
            coinThumb.setChg(BigDecimal.ZERO);
            coinThumb.setChange(BigDecimal.ZERO);
        }
    }

    @Override
    public void setExchangeRate(CoinExchangeRate coinExchangeRate) {
        this.coinExchangeRate = coinExchangeRate;
    }

    @Override
    public void update24HVolume(long time) {
        if (coinThumb != null) {
            synchronized (coinThumb) {
                String mergedUrl = "https://api.btcgateway.pro/swap-ex/market/detail/merged?contract_code=" + coin.getCoinSymbol() + "-USD";
                try {
                    String resultStr = HttpsUtil.doGet(mergedUrl);
                    JSONObject resultJson = JSON.parseObject(resultStr);
                    if (resultJson.containsKey("status") && resultJson.getString("status").equals("ok")) {
                        JSONObject tick = resultJson.getJSONObject("tick");
                        coinThumb.setHigh(tick.getBigDecimal("high").setScale(4, RoundingMode.DOWN));
                        coinThumb.setLow(tick.getBigDecimal("low").setScale(4, RoundingMode.DOWN));
                        coinThumb.setVolume(tick.getBigDecimal("vol").setScale(4, RoundingMode.DOWN));
                    } else {
                        Calendar calendar = Calendar.getInstance();
                        calendar.setTimeInMillis(time);
                        calendar.add(Calendar.HOUR_OF_DAY, -24);
                        long timeStart = calendar.getTimeInMillis();
                        BigDecimal volume = service.findTradeVolume(this.symbol, timeStart, time);
                        coinThumb.setVolume(volume.setScale(4, RoundingMode.DOWN));
                    }

                } catch (Exception e) {
                    log.error("update24HVolume is error : {}", e.getMessage());
                }

//
            }
        }
    }

    @Override
    public void initializeUsdRate(Integer type) {
        logger.info("symbol = {} ,baseCoin = {}", this.symbol, this.baseCoin);
        BigDecimal baseUsdRate = coinExchangeRate.getCoinLegalRate("USD", baseCoin);
        coinThumb.setBaseUsdRate(baseUsdRate);
        logger.info("setBaseUsdRate = ", baseUsdRate);
        BigDecimal multiply = coinThumb.getClose().multiply(baseUsdRate);
        logger.info("setUsdRate = ", multiply);
        coinThumb.setUsdRate(multiply);
    }


    @Override
    public String getBaseCoin() {
        return this.baseCoin;
    }

    @Override
    public void setScale(int coinScale, int baseCoinScale) {
        this.coinScale = coinScale;
        this.baseScale = baseCoinScale;
    }

    @Override
    public void autoGenerate() {
        DateFormat df = new SimpleDateFormat("HH:mm:ss");
        logger.info("auto generate 1min kline in {},data={}", df.format(new Date(currentKLine.getTime())), JSON.toJSONString(currentKLine));
//        if (coinThumb != null) {
        synchronized (currentKLine) {
            try {
                String result = HttpsUtil.doGet("https://api.btcgateway.pro/swap-ex/market/history/kline?contract_code=" + coin.getCoinSymbol() + "-USD&period=1min&size=1");
                JSONObject json = JSON.parseObject(result);
                if (json.containsKey("status") && "ok".equals(json.getString("status"))) {
                    List<JSONObject> list = json.getObject("data", List.class);
                    //没有成交价时存储上一笔成交价
                    JSONObject kline = list.get(0);

                    currentKLine.setOpenPrice(kline.getBigDecimal("open"));
                    currentKLine.setLowestPrice(kline.getBigDecimal("low"));
                    currentKLine.setHighestPrice(kline.getBigDecimal("high"));
                    currentKLine.setClosePrice(kline.getBigDecimal("close"));

                    currentKLine.setTime(kline.getLong("id") * 1000);
                    handleKLineStorage(currentKLine);

                    currentKLine.setOpenPrice(BigDecimal.ZERO);

                    if (currentKLine.getOpenPrice() == null || currentKLine.getOpenPrice().compareTo(BigDecimal.ZERO) == 0) {
                        currentKLine.setOpenPrice(kline.getBigDecimal("close"));
                        currentKLine.setLowestPrice(kline.getBigDecimal("close"));
                        currentKLine.setHighestPrice(kline.getBigDecimal("close"));
                        currentKLine.setClosePrice(kline.getBigDecimal("close"));
                    }
//                    currentKLine.setTime(kline.getLong("id") * 1000);
                    Calendar calendar = Calendar.getInstance();
                    calendar.set(Calendar.SECOND, 0);
                    calendar.set(Calendar.MILLISECOND, 0);
                    currentKLine.setTime(calendar.getTimeInMillis());
                    handleKLineStorage(currentKLine);
                    createNewKLine();
                }
            } catch (Exception e) {
                log.error("1分钟k线 autoGenerate : " + e.getMessage());
            }
        }
//        }
    }

    @Override
    public void setIsHalt(boolean status) {
        this.isHalt = status;
    }

    /**
     * 处理新生成的交易信息
     *
     * @param trades
     * @return
     */
    @Override
    public void process(List<ContractTrade> trades) {
        if (!isHalt) {
            if (trades == null || trades.size() == 0) {
                return;
            }
            synchronized (currentKLine) {
                for (ContractTrade exchangeTrade : trades) {
                    if (exchangeTrade.getType() != null && exchangeTrade.getType() == 1) {
                        //处理K线
                        processTrade(currentKLine, exchangeTrade);
                        //处理今日概况信息
                        logger.info("处理今日概况信息");
                        handleThumb(exchangeTrade);
                    }
                    //存储并推送成交信息
                    handleTradeStorage(exchangeTrade);
                }
            }
        }
    }

    public void processTrade(KLine kLine, ContractTrade exchangeTrade) {
        if (kLine.getClosePrice().compareTo(BigDecimal.ZERO) == 0) {
            //第一次设置K线值
            kLine.setOpenPrice(exchangeTrade.getPrice());
            kLine.setHighestPrice(exchangeTrade.getPrice());
            kLine.setLowestPrice(exchangeTrade.getPrice());
            kLine.setClosePrice(exchangeTrade.getPrice());
        } else {
            kLine.setHighestPrice(exchangeTrade.getPrice().max(kLine.getHighestPrice()));
            kLine.setLowestPrice(exchangeTrade.getPrice().min(kLine.getLowestPrice()));
            kLine.setClosePrice(exchangeTrade.getPrice());
        }
        kLine.setCount(kLine.getCount() + 1);
        kLine.setVolume(kLine.getVolume().add(exchangeTrade.getAmount()));
        BigDecimal turnover = exchangeTrade.getPrice().multiply(exchangeTrade.getAmount());
        kLine.setTurnover(kLine.getTurnover().add(turnover));
    }

    public void handleTradeStorage(ContractTrade exchangeTrade) {
        for (MarketHandler storage : handlers) {
            exchangeTrade.setAmountStr(exchangeTrade.getAmount().setScale(coinScale, RoundingMode.DOWN).toPlainString());
            exchangeTrade.setPriceStr(exchangeTrade.getPrice().setScale(baseScale, RoundingMode.DOWN).toPlainString());
            exchangeTrade.setNowpStr(exchangeTrade.getNowp().setScale(0).toPlainString());
            storage.handleTrade(symbol, exchangeTrade, coinThumb);
        }
    }

    public void handleKLineStorage(KLine kLine) {
        for (MarketHandler storage : handlers) {
            if (storage instanceof WebsocketMarketHandler) {
                storage.handleKLine(symbol, kLine);
            }
        }
    }

    public void handleThumb(ContractTrade exchangeTrade) {
        logger.info("handleThumb symbol = {}", this.symbol);
        synchronized (coinThumb) {
            if (coinThumb.getOpen().compareTo(BigDecimal.ZERO) == 0) {
                //第一笔交易记为开盘价
                coinThumb.setOpen(exchangeTrade.getPrice());
            }
            coinThumb.setHigh(exchangeTrade.getPrice().max(coinThumb.getHigh()));
            if (coinThumb.getLow().compareTo(BigDecimal.ZERO) == 0) {
                coinThumb.setLow(exchangeTrade.getPrice());
            } else {
                coinThumb.setLow(exchangeTrade.getPrice().min(coinThumb.getLow()));
            }
            coinThumb.setClose(exchangeTrade.getPrice());
            coinThumb.setVolume(coinThumb.getVolume().add(exchangeTrade.getNowp()).setScale(4, RoundingMode.UP));
            BigDecimal turnover = exchangeTrade.getPrice().multiply(exchangeTrade.getAmount()).setScale(4, RoundingMode.UP);
            coinThumb.setTurnover(coinThumb.getTurnover().add(turnover));
            BigDecimal change = coinThumb.getClose().subtract(coinThumb.getOpen());
            coinThumb.setChange(change);
            if (coinThumb.getOpen().compareTo(BigDecimal.ZERO) > 0) {
                coinThumb.setChg(change.divide(coinThumb.getOpen(), 4, BigDecimal.ROUND_UP));
            }
            coinThumb.setBaseUsdRate(coinExchangeRate.getCoinLegalRate("USD", baseCoin));
            coinThumb.setUsdRate(exchangeTrade.getPrice().multiply(coinThumb.getBaseUsdRate()));
            coinThumb.setCloseStr(coinThumb.getClose().setScale(baseScale, RoundingMode.DOWN).toPlainString());
            try {
                coinThumb.setCnyPrice(coinThumb.getClose().multiply(coinThumb.getBaseUsdRate()).multiply(BigDecimal.valueOf(6.8)).setScale(2, BigDecimal.ROUND_HALF_DOWN).toString());
            } catch (Exception e) {
                logger.info("初始化价格为空");
            }
            logger.info("thumb = {}", coinThumb);
        }
    }

    @Override
    public void addHandler(MarketHandler storage) {
        handlers.add(storage);
    }

    @Override
    public CoinThumb getThumb() {
        return coinThumb;
    }

    @Override
    public void setMarketService(MarketService service) {
        this.service = service;
    }

    @Override
    public void generateKLine(int range, int field, long time) {
        try {
            String rangeUnit = "";
            if (field == Calendar.MINUTE) {
                rangeUnit = "min";
            } else if (field == Calendar.HOUR_OF_DAY) {
                rangeUnit = "hour";
            } else if (field == Calendar.DAY_OF_WEEK) {
                rangeUnit = "week";
            } else if (field == Calendar.DAY_OF_YEAR) {
                rangeUnit = "day";
            } else if (field == Calendar.MONTH) {
//                rangeUnit = "month";
                rangeUnit = "mon";
            }
            if (range == 1 && field == Calendar.HOUR_OF_DAY) {
                range = 60;
                rangeUnit = "min";
            }
            String result = HttpsUtil.doGet("https://api.btcgateway.pro/swap-ex/market/history/kline?contract_code=" + coin.getCoinSymbol() + "-USD&period=" + range + rangeUnit + "&size=1");
            JSONObject json = JSON.parseObject(result).getJSONArray("data").getJSONObject(0);
            KLine kLine = new KLine();
            //k线的time值设置为起始时刻
            kLine.setTime(json.getLong("id") * 1000);
            kLine.setPeriod(range + rangeUnit);
            kLine.setOpenPrice(json.getBigDecimal("open"));
            kLine.setHighestPrice(json.getBigDecimal("high"));
            kLine.setLowestPrice(json.getBigDecimal("low"));
            kLine.setClosePrice(json.getBigDecimal("close"));
            handleKLineStorage(kLine);
            createNewKLine();
        } catch (Exception e) {
            log.error("生成k线 generateKLine: " + e.getMessage());
        }
    }

    @Override
    public KLine getKLine() {
        return currentKLine;
    }
}
